Skip to content

Enforce all react-next ESLint rules#154

Merged
ryota-murakami merged 6 commits into
mainfrom
codex/update-react-next-eslint-plugin
May 11, 2026
Merged

Enforce all react-next ESLint rules#154
ryota-murakami merged 6 commits into
mainfrom
codex/update-react-next-eslint-plugin

Conversation

@ryota-murakami

@ryota-murakami ryota-murakami commented May 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • verified @laststance/react-next-eslint-plugin is already on npm latest (2.2.0)
  • configure every exported @laststance/react-next rule at error severity
  • fix resulting lint failures by stabilizing custom-component props and moving component effects behind a named hook

Validation

  • pnpm validate
  • npx kill-port 9222
  • pnpm test:e2e

Summary by CodeRabbit

リリースノート

  • 新機能

    • レンダラー向けの副作用フックを追加して安定性を向上
  • バグ修正

    • フォーム内ボタンに type="button" を明示して誤送信を防止
    • 元に戻すトーストが明示的に閉じるよう改善(復元後の確実なクローズ)
  • パフォーマンス改善

    • 多数のイベント/ハンドラをメモ化して描画安定性と応答性を向上
  • 使い勝手改善

    • コピー先選択の状態管理とリセットを安定化

@vercel

vercel Bot commented May 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
skills-desktop Ready Ready Preview, Comment May 11, 2026 5:13pm

Request Review

@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

新規フック useComponentEffect を追加。多くのコンポーネントで副作用を React の useEffect から useComponentEffect に移行し、UI ハンドラを useCallback / useMemo で安定化。UndoToasttoastId を受けて自己破棄するよう API が変更され、Storybook と MainContent のトースト生成が更新。Redux に selectedCopyAgentIds を追加し、CopyToAgentsModal と関連ヘルパ/テストを更新。ESLint ルール生成が動的化。

Changes

Comprehensive Hook Optimization and Component Refactor

Layer / File(s) Summary
Hook 定義
src/renderer/src/hooks/useComponentEffect.ts
新規フック useComponentEffect(effect, deps?) を追加(React の useEffect をラップ)。
UndoToast / トースト経路
src/renderer/src/components/skills/UndoToast.tsx, src/renderer/src/components/layout/MainContent.tsx, .storybook/stories/Skills.stories.tsx
UndoToastPropstoastId: ToastId を追加、onUndoComplete を削除。Undo 実行後に toast.dismiss(toastId) を呼ぶ実装へ変更。MainContent と Storybook の呼出しで明示的に toastId を渡すよう更新。
Redux: copy-agent 選択状態
src/renderer/src/redux/slices/skillsSlice.ts, src/renderer/src/redux/*test.ts
selectedCopyAgentIds を state に追加。toggleCopyAgentSelection / clearCopyAgentSelection を追加し、setSkillToCopycopyToAgents 成功時にクリア。関連テストを更新。
CopyToAgentsModal とヘルパ
src/renderer/src/components/skills/CopyToAgentsModal.tsx, src/renderer/src/components/skills/agentSelectionHelpers.ts
選択状態をローカル state から Redux に移行。buildCopyAgentOptionViewModel を追加し、行レンダリングを CopyToAgentOption に抽出。ハンドラを useCallback 化し、行の checked/disabled/secondaryLabel ロジックを一元化。
広範な副作用移行
多数ファイル (src/renderer/...)
マウント/購読系の副作用(fetch、IPC、webview イベント 等)を useEffectuseComponentEffect に移行。
ハンドラの安定化 / 行コンポーネント化
多数ファイル (src/renderer/src/components/...)
複数の inline ハンドラを useCallback / useMemo に置換し、context/menu/row のクリック伝播等を統一。Add/Copy/Install モーダルの行を小コンポーネント化。
App / Toaster / UpdateToast
src/renderer/src/App.tsx, src/renderer/src/components/UpdateToast.tsx
ToastertoastOptions をモジュールスコープ定義に移動(型注釈)。UpdateToast のアクションハンドラを useCallback 化、dismiss ボタンを UI Button に変更。
ESLint 設定
eslint.config.mjs
@laststance/react-next/* ルールを配列から Object.fromEntries で動的生成するロジックを追加。
小修正・テスト
src/renderer/src/components/*, tests/*
SkipToMainContentLink の render 関数命名、FilterPill スタイル抽出、button の type="button" 追加、テストの preloadedState に selectedCopyAgentIds を追加等。

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant MainContent
  participant ToastLib
  participant UndoToast
  User->>MainContent: bulk-delete -> dispatch(show undo toast)
  MainContent->>ToastLib: toast(UndoToast, { id: toastId })
  UndoToast->>ToastLib: toast.dismiss(toastId) after onUndo completes
  UndoToast->>MainContent: onDismiss -> dispatch(clearUndoToast)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed タイトルは React ESLint ルールの強制という主要な変更を明確に説明しており、変更セット全体と直接関連しています。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/update-react-next-eslint-plugin

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter

codecov-commenter commented May 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 42.95533% with 166 lines in your changes missing coverage. Please review.
✅ Project coverage is 52.56%. Comparing base (b5ea95b) to head (470ff00).

Files with missing lines Patch % Lines
src/renderer/src/components/sidebar/SourceCard.tsx 0.00% 25 Missing ⚠️
src/renderer/settings/sections/General.tsx 0.00% 17 Missing ⚠️
...erer/src/components/sidebar/SyncConflictDialog.tsx 0.00% 17 Missing ⚠️
...rer/src/components/dashboard/DashboardPageTabs.tsx 0.00% 13 Missing ⚠️
src/renderer/src/components/skills/SkillItem.tsx 58.62% 8 Missing and 4 partials ⚠️
...r/src/components/marketplace/MarketplaceSearch.tsx 0.00% 9 Missing ⚠️
...nderer/src/components/skills/CopyToAgentsModal.tsx 65.38% 6 Missing and 3 partials ⚠️
...nderer/src/components/marketplace/InstallModal.tsx 0.00% 8 Missing ⚠️
...derer/src/components/dashboard/DashboardCanvas.tsx 0.00% 7 Missing ⚠️
src/renderer/src/components/UpdateToast.tsx 0.00% 5 Missing ⚠️
... and 21 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #154      +/-   ##
==========================================
+ Coverage   52.43%   52.56%   +0.12%     
==========================================
  Files         176      177       +1     
  Lines        4350     4429      +79     
  Branches      915      920       +5     
==========================================
+ Hits         2281     2328      +47     
- Misses       1872     1903      +31     
- Partials      197      198       +1     
Flag Coverage Δ
unittests 52.56% <42.95%> (+0.12%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/renderer/src/components/skills/UnlinkDialog.tsx (1)

107-111: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

handleUnlinkの依存配列がコールバック再生成を引き起こしています(Line 139)

Line 107-111のcopyは毎レンダー新しいオブジェクトが生成されるため、Line 139の依存配列に含めるとhandleUnlinkは毎回再生成されます。React.memoでコンポーネント化されていても、不安定なコールバック参照が下流への不要な再レンダーを引き起こす可能性があります。copyuseMemoでメモ化してください。

差分案
-import React, { useCallback } from 'react'
+import React, { useCallback, useMemo } from 'react'
@@
-    const copy = getUnlinkCopy(
-      variant,
-      skillToUnlink?.skill.name ?? '',
-      skillToUnlink?.symlink.agentName ?? '',
-    )
+    const copy = useMemo(
+      () =>
+        getUnlinkCopy(
+          variant,
+          skillToUnlink?.skill.name ?? '',
+          skillToUnlink?.symlink.agentName ?? '',
+        ),
+      [variant, skillToUnlink?.skill.name, skillToUnlink?.symlink.agentName],
+    )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/src/components/skills/UnlinkDialog.tsx` around lines 107 - 111,
getUnlinkCopyで毎レンダー新しいオブジェクトを作っているためhandleUnlinkの依存配列に入れるとコールバックが毎回再生成されます。解決するには現在のconst
copy =
getUnlinkCopy(...)をuseMemoでラップして、依存関係にvariant、skillToUnlink?.skill.name、skillToUnlink?.symlink.agentNameだけを入れてメモ化し、handleUnlinkの依存配列にはそのメモ化されたcopyを使うようにしてください(参照シンボル:
getUnlinkCopy, copy, handleUnlink)。
src/renderer/src/components/layout/MainContent.tsx (1)

404-423: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Undoトーストのdismissで新しいUndo状態を誤って消す競合があります。

Line 404-406 / 421-423 は clearUndoToast() を無条件実行しているため、先に出したトーストが閉じたタイミングで、後続トーストの undoToast まで消える可能性があります。toastId 一致時のみクリアする形にしてください。

差分案(このファイル内)
-        const handleToastDismissed = (): void => {
-          dispatch(clearUndoToast())
-        }
         const toastId: ToastId = `bulk-delete-${Date.now()}`
+        const handleToastDismissed = (): void => {
+          dispatch(clearUndoToast({ id: toastId }))
+        }
追加実装案(reducer側のガード)
// uiSlice 側のイメージ
clearUndoToast: (state, action: PayloadAction<{ id: ToastId }>) => {
  if (state.undoToast?.id === action.payload.id) {
    state.undoToast = null
  }
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/src/components/layout/MainContent.tsx` around lines 404 - 423,
The current handleToastDismissed unconditionally dispatches clearUndoToast(),
which can clear a newer toast's state; update handleToastDismissed to dispatch
clearUndoToast with the toastId (use the toastId constant captured by the
closure) and change the ui reducer clearUndoToast to accept a payload { id:
ToastId } and only clear state.undoToast when state.undoToast?.id ===
action.payload.id; keep the toast invocation (toast(..., { id: toastId,
duration: UNDO_WINDOW_MS, onDismiss: handleToastDismissed, onAutoClose:
handleToastDismissed })) and ensure the reducer name clearUndoToast and the
toastId variable are used to locate the changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@eslint.config.mjs`:
- Around line 6-11: 現在の自動有効化ロジック (laststanceReactNextRules =
Object.fromEntries(Object.keys(laststanceReactNextPlugin.rules ?? {}).map(...)))
はプラグイン更新で新ルールが勝手に error 有効化されCI破壊を招くため、laststanceReactNextPlugin.rules
の全キーを使う代わりに明示的なルールリストを用いるよう修正してください — 具体的には laststanceReactNextRules
を自動生成から、既知の許可されたルール名の配列(whitelistedRules など)を定義してその配列を map/fromEntries して
'error' を割り当てるか、既存の Object.keys(...) をフィルタして許可リストに存在するものだけを有効化する実装に置き換えてください。

In `@src/renderer/settings/sections/General.tsx`:
- Around line 161-172: handleSaveCurrentSize currently awaits
window.electron.window.getMainBounds() without catching a rejection, causing
unhandled promise rejections when invoked via handleSaveCurrentSizeClick; wrap
the await in a try/catch inside handleSaveCurrentSize, and in the catch
setIsMainWindowAvailable(false) and return (optionally log the error), ensuring
updateSettings({ windowSize: bounds }) only runs on success and existing
handleSaveCurrentSizeClick can continue to call void handleSaveCurrentSize().

In `@src/renderer/src/components/sidebar/SourceCard.tsx`:
- Around line 51-57: handleRefresh currently fires multiple thunks via
Promise.all but doesn't detect rejection; change handleRefresh into an async
callback that awaits Promise.all of the dispatched thunks' unwrap() results
(e.g., await Promise.all([dispatch(fetchSourceStats()).unwrap(),
dispatch(fetchSkills()).unwrap(), dispatch(fetchAgents()).unwrap()])) and wrap
that await in try/catch to handle failures (notify user/log error inside catch).
Keep useCallback and dispatch references (handleRefresh, fetchSourceStats,
fetchSkills, fetchAgents) and ensure the caller still uses void handleRefresh()
if previously used.

In `@src/renderer/src/components/skills/UndoToast.tsx`:
- Around line 32-34: The JSDoc for UndoToast is out of date: update comment text
around the toastId usage to remove references to onUndoComplete and instead
document that UndoToast (used by MainContent) will dismiss via
toast.dismiss(toastId); specifically, edit the JSDoc entries that mention
onUndoComplete (the blocks around lines referencing the example/description) to
explain the explicit Sonner id (toastId) and show using toast.dismiss(toastId)
as the undo completion mechanism so the docs match the UndoToast component and
its toastId prop.

In `@src/renderer/src/components/UpdateToast.tsx`:
- Around line 41-43: The close-button handler handleCloseButtonClick is not
memoized like the other handlers; either wrap it with useCallback (e.g., create
handleCloseButtonClick = useCallback(() => handleDismiss(), [handleDismiss])) to
match the pattern used for other handlers, or remove the wrapper entirely and
pass handleDismiss directly to the onClick prop; update the reference in the
component (where handleCloseButtonClick is used) to reflect the chosen approach
so handlers remain consistent and stable.

---

Outside diff comments:
In `@src/renderer/src/components/layout/MainContent.tsx`:
- Around line 404-423: The current handleToastDismissed unconditionally
dispatches clearUndoToast(), which can clear a newer toast's state; update
handleToastDismissed to dispatch clearUndoToast with the toastId (use the
toastId constant captured by the closure) and change the ui reducer
clearUndoToast to accept a payload { id: ToastId } and only clear
state.undoToast when state.undoToast?.id === action.payload.id; keep the toast
invocation (toast(..., { id: toastId, duration: UNDO_WINDOW_MS, onDismiss:
handleToastDismissed, onAutoClose: handleToastDismissed })) and ensure the
reducer name clearUndoToast and the toastId variable are used to locate the
changes.

In `@src/renderer/src/components/skills/UnlinkDialog.tsx`:
- Around line 107-111:
getUnlinkCopyで毎レンダー新しいオブジェクトを作っているためhandleUnlinkの依存配列に入れるとコールバックが毎回再生成されます。解決するには現在のconst
copy =
getUnlinkCopy(...)をuseMemoでラップして、依存関係にvariant、skillToUnlink?.skill.name、skillToUnlink?.symlink.agentNameだけを入れてメモ化し、handleUnlinkの依存配列にはそのメモ化されたcopyを使うようにしてください(参照シンボル:
getUnlinkCopy, copy, handleUnlink)。
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: dee2bf2f-a80c-4434-8d10-337e5ca2b330

📥 Commits

Reviewing files that changed from the base of the PR and between b5ea95b and caed3e0.

📒 Files selected for processing (43)
  • .storybook/stories/Skills.stories.tsx
  • eslint.config.mjs
  • src/renderer/settings/sections/About.tsx
  • src/renderer/settings/sections/Agents.tsx
  • src/renderer/settings/sections/General.tsx
  • src/renderer/src/App.tsx
  • src/renderer/src/components/SkipToMainContentLink.tsx
  • src/renderer/src/components/UpdateToast.tsx
  • src/renderer/src/components/dashboard/DashboardCanvas.tsx
  • src/renderer/src/components/dashboard/DashboardEditToolbar.tsx
  • src/renderer/src/components/dashboard/DashboardPageTabs.tsx
  • src/renderer/src/components/dashboard/widgets/BookmarksWidget.tsx
  • src/renderer/src/components/dashboard/widgets/CoverageWidget.tsx
  • src/renderer/src/components/dashboard/widgets/LeaderboardWidget.tsx
  • src/renderer/src/components/layout/MainContent.tsx
  • src/renderer/src/components/marketplace/InstallModal.tsx
  • src/renderer/src/components/marketplace/MarketplaceSearch.tsx
  • src/renderer/src/components/marketplace/MarketplaceSkillPreview.tsx
  • src/renderer/src/components/marketplace/RankingTabs.tsx
  • src/renderer/src/components/marketplace/SkillRowMarketplace.tsx
  • src/renderer/src/components/marketplace/SkillsMarketplace.tsx
  • src/renderer/src/components/sidebar/AgentDeleteDialog.tsx
  • src/renderer/src/components/sidebar/AgentItem.tsx
  • src/renderer/src/components/sidebar/AgentsSection.tsx
  • src/renderer/src/components/sidebar/BookmarkDetailModal.tsx
  • src/renderer/src/components/sidebar/CleanupAgentDialog.tsx
  • src/renderer/src/components/sidebar/SidebarFooter.tsx
  • src/renderer/src/components/sidebar/SourceCard.tsx
  • src/renderer/src/components/sidebar/SyncConfirmDialog.tsx
  • src/renderer/src/components/sidebar/SyncConflictDialog.tsx
  • src/renderer/src/components/sidebar/SyncResultDialog.tsx
  • src/renderer/src/components/skills/AddSymlinkModal.tsx
  • src/renderer/src/components/skills/CopyToAgentsModal.tsx
  • src/renderer/src/components/skills/FileContent.tsx
  • src/renderer/src/components/skills/SearchBox.tsx
  • src/renderer/src/components/skills/SelectionToolbar.tsx
  • src/renderer/src/components/skills/SkillItem.tsx
  • src/renderer/src/components/skills/SkillsList.tsx
  • src/renderer/src/components/skills/UndoToast.tsx
  • src/renderer/src/components/skills/UnlinkDialog.tsx
  • src/renderer/src/components/theme/ThemeSelector.tsx
  • src/renderer/src/components/ui/FilterPill.tsx
  • src/renderer/src/hooks/useComponentEffect.ts

Comment thread eslint.config.mjs
Comment thread src/renderer/settings/sections/General.tsx
Comment thread src/renderer/src/components/sidebar/SourceCard.tsx Outdated
Comment thread src/renderer/src/components/skills/UndoToast.tsx
Comment thread src/renderer/src/components/UpdateToast.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/renderer/src/components/skills/UndoToast.tsx (1)

103-114: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

useCallback の依存配列が派生値と基底値を混在させている。

Line 114 の deps [canUndo, onUndo, toastId, tombstoneIds] は、派生値 canUndoisUndoableOperation && !isRestoring && remainingMs > 0 から計算)と、その計算元である tombstoneIds の両方を含んでいる。これにより不要な callback 再生成が発生する。

2つの修正案:

案1(推奨): canUndo の計算をコールバック内に移動し、基底値のみを deps に含める。

案2: canUndo を削除し、基底値 [isRestoring, remainingMs, tombstoneIds, onUndo, toastId] を deps に列挙。

♻️ 案1の実装例
-  const canUndo = isUndoableOperation && !isRestoring && remainingMs > 0
-
   const handleUndoClick = useCallback(async (): Promise<void> => {
+    const canUndo = isUndoableOperation && !isRestoring && remainingMs > 0
     if (!canUndo) return
     setIsRestoring(true)
     try {
       await onUndo(tombstoneIds)
     } finally {
       toast.dismiss(toastId)
     }
-  }, [canUndo, onUndo, toastId, tombstoneIds])
+  }, [isUndoableOperation, isRestoring, remainingMs, onUndo, toastId, tombstoneIds])

Line 160 の disabled={!canUndo} のため、外側で canUndo は引き続き必要。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/src/components/skills/UndoToast.tsx` around lines 103 - 114, The
useCallback for handleUndoClick currently mixes a derived value canUndo with its
bases causing needless re-renders; move the canUndo calculation
(isUndoableOperation && !isRestoring && remainingMs > 0) into handleUndoClick so
the callback uses only base values, keep the external canUndo (used for
disabled={!canUndo}) as-is, and update the dependency array of handleUndoClick
to the base symbols [isUndoableOperation, isRestoring, remainingMs,
tombstoneIds, onUndo, toastId] so the callback only re-creates when underlying
inputs change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/renderer/src/components/skills/CopyToAgentsModal.tsx`:
- Around line 43-45: selectedAgents is currently local state reset in
CopyToAgentsModal via useComponentEffect (setSelectedAgents) and must be moved
to the skills Redux slice: add selectedAgents state to skillsSlice, implement
actions like toggleSelectedAgent(agentId) and clearSelectedAgents(), update
selectors (selectSelectedAgents) and replace all local
useState/setSelectedAgents usage in CopyToAgentsModal to
useSelector(selectSelectedAgents) and dispatch(toggleSelectedAgent(...)) /
dispatch(clearSelectedAgents()) (including the effect that currently resets on
skillToCopy — replace setSelectedAgents([]) with dispatch(clearSelectedAgents())
inside the useComponentEffect). Ensure existing component logic references the
new selector/action names and remove the local selectedAgents state and its
setters.

---

Outside diff comments:
In `@src/renderer/src/components/skills/UndoToast.tsx`:
- Around line 103-114: The useCallback for handleUndoClick currently mixes a
derived value canUndo with its bases causing needless re-renders; move the
canUndo calculation (isUndoableOperation && !isRestoring && remainingMs > 0)
into handleUndoClick so the callback uses only base values, keep the external
canUndo (used for disabled={!canUndo}) as-is, and update the dependency array of
handleUndoClick to the base symbols [isUndoableOperation, isRestoring,
remainingMs, tombstoneIds, onUndo, toastId] so the callback only re-creates when
underlying inputs change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 894311fb-f862-4063-a3fb-91cd0a0991db

📥 Commits

Reviewing files that changed from the base of the PR and between caed3e0 and 562e6a2.

📒 Files selected for processing (9)
  • eslint.config.mjs
  • src/renderer/settings/sections/General.tsx
  • src/renderer/src/App.tsx
  • src/renderer/src/components/UpdateToast.tsx
  • src/renderer/src/components/sidebar/SourceCard.tsx
  • src/renderer/src/components/skills/AddSymlinkModal.tsx
  • src/renderer/src/components/skills/CopyToAgentsModal.tsx
  • src/renderer/src/components/skills/UndoToast.tsx
  • src/renderer/src/components/ui/FilterPill.tsx

Comment thread src/renderer/src/components/skills/CopyToAgentsModal.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/renderer/src/redux/slices/skillsSlice.ts (1)

449-455: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

copyToAgents.fulfilled で Add関連stateをクリアする必要性を確認

Line 452-453 で skillToAddSymlinksselectedAddAgentIds をクリアしていますが、Copy操作は Add操作と独立しているため、Add関連stateをクリアする論理的根拠が不明確です。createSymlinks.fulfilled (436-440) では Add関連stateのみクリアしており、非対称です。

2つのモーダルが同時に開かないなら影響は小さいですが、意図的な"全モーダルクリア"ポリシーでない限り、Copy完了時は Copy関連state(skillToCopy, selectedCopyAgentIds)のみクリアする方が明確です。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/src/redux/slices/skillsSlice.ts` around lines 449 - 455, The
copyToAgents.fulfilled reducer is clearing Add-related state
(skillToAddSymlinks, selectedAddAgentIds) even though Add and Copy are
independent; update the copyToAgents.fulfilled handler to only clear
copy-related fields (set copying = false, skillToCopy = null,
selectedCopyAgentIds = []), leaving skillToAddSymlinks and selectedAddAgentIds
untouched (match the asymmetry used in createSymlinks.fulfilled which only
clears Add-related state).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/renderer/src/components/skills/CopyToAgentsModal.tsx`:
- Around line 194-202: Wrap handleRowClick in useCallback to keep consistency
with handleToggle: change the plain function handleRowClick to a memoized
callback (useCallback) that calls handleToggle, with the same dependency set
(agentId, disabled, onToggle) or simply [handleToggle] if you prefer; update the
reference where the intrinsic <div> row click handler uses handleRowClick so it
receives the memoized function. Ensure the exported/local symbol names remain
handleRowClick and handleToggle.
- Line 223: The Checkbox handler handleToggle used in CopyToAgentsModal should
accept the Radix signature (checked: boolean | 'indeterminate') => void instead
of () => void; update the handleToggle function declaration (and any references)
to receive a single parameter typed as boolean | 'indeterminate' and simply
ignore or use it as needed, ensuring the onCheckedChange={handleToggle} is
type-safe in the CopyToAgentsModal component.

---

Outside diff comments:
In `@src/renderer/src/redux/slices/skillsSlice.ts`:
- Around line 449-455: The copyToAgents.fulfilled reducer is clearing
Add-related state (skillToAddSymlinks, selectedAddAgentIds) even though Add and
Copy are independent; update the copyToAgents.fulfilled handler to only clear
copy-related fields (set copying = false, skillToCopy = null,
selectedCopyAgentIds = []), leaving skillToAddSymlinks and selectedAddAgentIds
untouched (match the asymmetry used in createSymlinks.fulfilled which only
clears Add-related state).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: aaba11c7-e6a4-438a-aa49-95c5f3a4ae05

📥 Commits

Reviewing files that changed from the base of the PR and between 562e6a2 and 9ddcd82.

📒 Files selected for processing (5)
  • src/renderer/src/components/skills/CopyToAgentsModal.tsx
  • src/renderer/src/components/skills/SkillsList.browser.test.tsx
  • src/renderer/src/redux/selectors.test.ts
  • src/renderer/src/redux/slices/skillsSlice.test.ts
  • src/renderer/src/redux/slices/skillsSlice.ts

Comment thread src/renderer/src/components/skills/CopyToAgentsModal.tsx Outdated
Comment thread src/renderer/src/components/skills/CopyToAgentsModal.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/renderer/src/components/skills/CopyToAgentsModal.tsx`:
- Around line 121-141: The JSX currently computes selection/disabled state
inline inside targetAgents.map using occupiedAgentReasonById, selectedAgents,
copying and isSourceUnavailable and passes them to CopyToAgentOption; extract
that conditional logic into a pure helper in agentSelectionHelpers (e.g., a
function buildAgentViewModel(agent, { occupiedAgentReasonById, selectedAgents,
copying, isSourceUnavailable }) that returns { agentId, name, exists, checked,
disabled, occupiedReason }) and change the map to consume the view model and
only render CopyToAgentOption and pass viewModel fields plus onToggle
(handleAgentToggle); apply the same extraction for the similar block around
lines 236-245 so rendering code is purely presentational and the logic is
unit-testable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d4ab28b6-e12f-420e-aa17-cba9f44c0a1c

📥 Commits

Reviewing files that changed from the base of the PR and between 9ddcd82 and 15c16c5.

📒 Files selected for processing (1)
  • src/renderer/src/components/skills/CopyToAgentsModal.tsx

Comment thread src/renderer/src/components/skills/CopyToAgentsModal.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/renderer/src/components/skills/CopyToAgentsModal.tsx`:
- Around line 46-49: The effect using useComponentEffect currently depends on
the entire skillToCopy object which causes clearCopyAgentSelection() to run on
any reference change; update the dependency to a stable identifier or modal-open
flag instead (e.g., use skillToCopy?.id or an isModalOpen prop/state) so that
clearCopyAgentSelection() only runs when the modal actually opens/closes; keep
the effect and dispatch(clearCopyAgentSelection()) but replace the dependency
array entry skillToCopy with the chosen stable symbol and ensure the modal
open/close lifecycle drives the reset.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 603c7041-53e7-4a0b-82c5-2a28bde7e570

📥 Commits

Reviewing files that changed from the base of the PR and between 15c16c5 and 4fde6ba.

📒 Files selected for processing (3)
  • src/renderer/src/components/skills/CopyToAgentsModal.tsx
  • src/renderer/src/components/skills/agentSelectionHelpers.test.ts
  • src/renderer/src/components/skills/agentSelectionHelpers.ts

Comment thread src/renderer/src/components/skills/CopyToAgentsModal.tsx Outdated
@ryota-murakami ryota-murakami merged commit cd4f322 into main May 11, 2026
9 checks passed
@ryota-murakami ryota-murakami deleted the codex/update-react-next-eslint-plugin branch May 11, 2026 17:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants